[CDK]AWS WorkSpacesへのログインを検知してSlack通知する
吉川@広島です。
【新機能】WorkSpacesのログインイベントのトラッキングが可能になりました | DevelopersIO
案件でこちらの機能を使用する機会があったため、共有したいと思います。
大まかな構成は上記記事を踏襲していますが、差分は以下になります。
- CDKで構築する
- SNSからの通知先をメールではなくAWS Chatbot(Slack)とする
- Lambdaコードの言語はPythonではなくNode.js(TypeScript)とする
AWS Chatbotの下準備
CloudWatch AlarmをAWS ChatbotからSlack通知する仕組みをCDKで作ってみた | DevelopersIO
こちらの「AWS Chatbot の Workspace Configuration を GUI から作成」の手順を実施します。
CDKコード
cdkコマンドでプロジェクトを生成します。
npx aws-cdk init --language typescript
// bin/cdk.ts #!/usr/bin/env node import 'source-map-support/register' import * as cdk from '@aws-cdk/core' import { CdkStack } from '../lib/cdk-stack' const app = new cdk.App() new CdkStack(app, 'workspaces-alarm-stack', { slackWorkspaceId: 'xxxxxxxxx', // SlackワークスペースID slackChannelId: 'xxxxxxxxx', // SlackチャンネルID })
// lib/cdk-stack.ts import * as cdk from '@aws-cdk/core' import * as sns from '@aws-cdk/aws-sns' import * as iam from '@aws-cdk/aws-iam' import * as chatbot from '@aws-cdk/aws-chatbot' import * as lambda from '@aws-cdk/aws-lambda' import * as events from '@aws-cdk/aws-events' import * as eventsTargets from '@aws-cdk/aws-events-targets' export interface MyProps { readonly slackChannelId: string readonly slackWorkspaceId: string } export class CdkStack extends cdk.Stack { constructor( scope: cdk.Construct, id: string, props?: cdk.StackProps & MyProps ) { super(scope, id, props) /** * SNS */ const topic = new sns.Topic(this, 'topic') topic.addToResourcePolicy( new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['SNS:Publish'], principals: [new iam.ServicePrincipal('events.amazonaws.com')], resources: [topic.topicArn], }) ) /** * Chatbot */ const chatbotRole = new iam.Role(this, 'chatbot-role', { assumedBy: new iam.ServicePrincipal('sns.amazonaws.com'), }) chatbotRole.addToPolicy( new iam.PolicyStatement({ resources: ['*'], actions: ['cloudwatch:*'], }) ) new chatbot.CfnSlackChannelConfiguration(this, 'slack-channel-config', { configurationName: 'slack-channel-config', iamRoleArn: chatbotRole.roleArn, slackChannelId: props!.slackChannelId, slackWorkspaceId: props!.slackWorkspaceId, snsTopicArns: [topic.topicArn], loggingLevel: 'ERROR', }) /** * Lambda */ const fn = new lambda.Function(this, 'fn', { runtime: lambda.Runtime.NODEJS_14_X, code: lambda.Code.fromAsset('/path/to/dist'), // Bundle後のLambdaコードのPATHを指定 handler: 'index.handler', environment: { SNS_TOPIC_ARN: topic.topicArn, }, }) topic.grantPublish(fn) /** * CloudWatch Events */ new events.Rule(this, 'rule', { eventPattern: { source: ['aws.workspaces'], detailType: ['WorkSpaces Access'], }, targets: [new eventsTargets.LambdaFunction(fn)], }) } }
Lambdaコード
CloudWatch Eventsをトリガーとして起動するLambdaコードを書きます。せっかくなので
- TypeScriptで書いて
- AWS SDK v3を使って
- esbuildでバンドル
という感じでいきます。
npm i -S @aws-sdk/client-sns npm i -D esbuild @types/node
SNSにPublishするだけのシンプルなLambda関数です。
import { PublishCommand, SNSClient } from '@aws-sdk/client-sns' export const handler = (event: unknown) => { console.log(JSON.stringify(event)) const snsClient = new SNSClient({}) snsClient.send( new PublishCommand({ TopicArn: process.env.SNS_TOPIC_ARN!, Message: JSON.stringify(event, null, 2), Subject: 'WorkSpaces Access Notification', }) ) }
npx esbuild src/index.ts --platform=node --target=node14 --bundle --outfile=dist/index.js
動作確認
以上の設定でデプロイ後、AWS WorkSpacesのインスタンスにログインすると通知が来ることを確認できました。